/****************************************************************************
 * Copyright (C) 2013 Dj_Skual
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ****************************************************************************/
#include "ENandMiiTask.hpp"
#include "../ManageTools.h"
#include "../../Controls/Application.h"
#include "../../Menu/Explorer.h"
#include "../../Miis/MiiInstaller.h"
#include "../../FileOperations/fileops.h"

ENandMiiTask::ENandMiiTask(short Type, std::string destpath)
	: destPath(destpath)
	, type(Type)
	, canceled(false)
	, window(NULL)
{
	ThreadedTaskHandler::Instance()->AddTask(this);
}

void ENandMiiTask::OnCancelClick()
{
	canceled = true;
}

std::string ENandMiiTask::FixMiiName(std::string filename)
{
	filename.assign(StringReplace(filename, ":", "&cl;"));
	filename.assign(StringReplace(filename, "*", "&st;"));
	filename.assign(StringReplace(filename, "\"", "&qt;"));
	filename.assign(StringReplace(filename, "?", "&qm;"));
	filename.assign(StringReplace(filename, "|", "&vb;"));
	filename.assign(StringReplace(filename, "<", "&lt;"));
	filename.assign(StringReplace(filename, ">", "&gt;"));
	
	return filename;
}

void ENandMiiTask::Execute(void)
{
	int selected = CurrentBrowser()->GetSelIndex();
	
	std::string emuPath = CurrentBrowser()->GetCurrentPath();
	int emuNum = ManageTools::GetENandNumber(emuPath);
		
	if(type == EXTRACT_TO_DEV)
		window = new ManageProgressWindow(tr("Extracting..."));
	else if(type == DELETE_FROM_ENAND)
		window = new ManageProgressWindow(tr("Deleting..."));
	else if(type == INSTALL_TO_NAND || type == INSTALL_TO_ENAND)
		window = new ManageProgressWindow(tr("Installing..."));
	window->Canceled.connect(this, &ENandMiiTask::OnCancelClick);
	
	int result = -1;
	if(type == DELETE_FROM_ENAND)
	{
		result = Mii::DeleteEmu(CurrentBrowser()->GetMiiPosition(selected), emuNum);
	}
	else if(type == EXTRACT_TO_DEV)
	{
		if(destPath.empty())
		{
			delete window;
			End(this, -1);
			return;
		}
		
		CreateSubfolder(destPath);
		
		//! Get extract file path
		if (destPath[destPath.size()-1] != '/')
			destPath += "/";
		std::string name = wstr2str(CurrentBrowser()->GetMiiName(selected));
		std::string finalPath = fmt("%s%s.miigx", destPath.c_str(), FixMiiName(name).c_str());
		
		std::string EmuMiiDBPath = emuPath;
		EmuMiiDBPath += MII_FILE;
		
		FILE * miisrc = fopen(EmuMiiDBPath.c_str(), "rb");
		if (miisrc)
		{
			int pos = CurrentBrowser()->GetMiiPosition(selected);
			fseek(miisrc, MII_HEADER+(pos*MII_SIZE), SEEK_SET);
			
			u8* memory = (u8*)memalign(32, MII_SIZE);
			if(memory)
			{
				//! Read Mii
				if (fread(memory, 1, MII_SIZE, miisrc) == MII_SIZE)
				{
					//! Open destination file
					FILE * miidest = fopen(finalPath.c_str(), "wb");
					if(miidest)
					{
						//! Write file
						if (fwrite(memory, 1, MII_SIZE, miidest) == MII_SIZE)
							result = 1;
						fclose(miidest);
					}
				}
				free(memory);
				memory = NULL;
			}
			fclose(miisrc);
		}
	}
	else if(type == INSTALL_TO_NAND)
	{
		int position = -1; //! position of the mii in eNand file
		MiiBrowser * browser = new MiiBrowser();
		
		for(int n = 0; n < browser->GetEntrieCount(); n++)
		{
			if(!browser->GetMiiName(n).compare(CurrentBrowser()->GetMiiName(selected)))
			{
				window->Hide();
				
				ManageButtons * overWriteButtons = new ManageButtons(tr( "is already installed." ), 0, tr( "OverWrite" ), tr( "Duplicate" ), tr( "Cancel" ));
				overWriteButtons->SetEffect(EFFECT_FADE, 20);
				overWriteButtons->SetAlignment(ALIGN_CENTER | ALIGN_MIDDLE);
				overWriteButtons->SetPosition(0, 80);
				Application::Instance()->Append(overWriteButtons);
				Application::Instance()->SetUpdateOnly(overWriteButtons);
				
				int choice = 0;
				while (!(choice = overWriteButtons->GetChoice()))
				{	
					if(Application::isClosing())
					{
						Application::Instance()->UnsetUpdateOnly(overWriteButtons);
						Application::Instance()->Remove(overWriteButtons);
						delete overWriteButtons;
						delete browser;
						delete window;
						return;
					}
					else
						usleep(50);
				}
				
				overWriteButtons->SetEffect(EFFECT_FADE, -20);
				while (overWriteButtons->IsAnimated())
					usleep(50);
				Application::Instance()->UnsetUpdateOnly(overWriteButtons);
				Application::Instance()->Remove(overWriteButtons);
				delete overWriteButtons;
				
				if(choice != 3)
				{
					window->Show();
					
					if(choice == 1)
						position = browser->GetMiiPosition(n);
					else
						position = MiiTools::FindFirstFree(browser);
					
					n = browser->GetEntrieCount();
				}
				else
				{
					canceled = true;
					n = browser->GetEntrieCount();
				}
			}
		}
		if(!canceled && (position < 0))
			position = MiiTools::FindFirstFree(browser);
		
		delete browser;
		
		if(!canceled)
			result = Mii::EmuToNand(CurrentBrowser()->GetMiiPosition(selected), position, emuNum);
	}
	else if(type == INSTALL_TO_ENAND)
	{
		int srcNum = emuNum;
		int destNum = ManageTools::GetENandNumber(destPath);
		
		int srcPos = CurrentBrowser()->GetMiiPosition(selected);
		int destPos = -1;
		
		EMiiBrowser * browser = new EMiiBrowser();
		browser->GetList(destPath);
		
		for(int n = 0; n < browser->GetEntrieCount(); n++)
		{
			if(!browser->GetMiiName(n).compare(CurrentBrowser()->GetMiiName(selected)))
			{
				window->Hide();
				
				ManageButtons * overWriteButtons = new ManageButtons(tr( "is already installed." ), 0, tr( "OverWrite" ), tr( "Duplicate" ), tr( "Cancel" ));
				overWriteButtons->SetEffect(EFFECT_FADE, 20);
				overWriteButtons->SetAlignment(ALIGN_CENTER | ALIGN_MIDDLE);
				overWriteButtons->SetPosition(0, 80);
				Application::Instance()->Append(overWriteButtons);
				Application::Instance()->SetUpdateOnly(overWriteButtons);
				
				int choice = 0;
				while (!(choice = overWriteButtons->GetChoice()))
				{	
					if(Application::isClosing())
					{
						Application::Instance()->UnsetUpdateOnly(overWriteButtons);
						Application::Instance()->Remove(overWriteButtons);
						delete overWriteButtons;
						delete browser;
						delete window;
						return;
					}
					else
						usleep(50);
				}
				
				overWriteButtons->SetEffect(EFFECT_FADE, -20);
				while (overWriteButtons->IsAnimated())
					usleep(50);
				Application::Instance()->UnsetUpdateOnly(overWriteButtons);
				Application::Instance()->Remove(overWriteButtons);
				delete overWriteButtons;
				
				if(choice != 3)
				{
					window->Show();
					
					if(choice == 1)
						destPos = browser->GetMiiPosition(n);
					else
						destPos = MiiTools::FindFirstFree(browser);
					
					n = browser->GetEntrieCount();
				}
				else
				{
					canceled = true;
					n = browser->GetEntrieCount();
				}
			}
		}
		if(!canceled && (destPos < 0))
			destPos = MiiTools::FindFirstFree(browser);
		
		delete browser;
		
		if(!canceled)
			result = Mii::EmuToEmu(srcPos, srcNum, destPos, destNum);
	}
	
	delete window;
	
	if(canceled)
		result = 0;
	
	End(this, result);
}
